/*
 * Copyright (C) 2010 Moduad Co., Ltd.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package yxt.push.org.androidpn.client;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import cn.com.winning.ecare.common.MyApplication;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiManager.WifiLock;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.provider.Settings.Secure;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;

/**
 * Service that continues to run in background and respond to the push
 * notification events from the server. This should be registered as service in
 * AndroidManifest.xml.
 * 
 * @author Sehwan Noh (devnoh@gmail.com)
 */
public class NotificationService extends Service
{

	private static final String LOGTAG = LogUtil.makeLogTag(NotificationService.class);

	public static final String SERVICE_NAME = "yxt.push.org.androidpn.client.NotificationService";

	private TelephonyManager telephonyManager;

	private PowerManager powerManager;
	private WakeLock wakeLock;

	private WifiManager wifiManager;
	private WifiLock wifiLock;

	// private ConnectivityManager connectivityManager;

	private BroadcastReceiver notificationReceiver;

	private BroadcastReceiver connectivityReceiver;

	private PhoneStateListener phoneStateListener;

	private ExecutorService executorService;

	private TaskSubmitter taskSubmitter;

	private TaskTracker taskTracker;

	private XmppManager xmppManager;

	private SharedPreferences sharedPrefs;

	private String deviceId;

	private MyApplication myApplication;

	public NotificationService()
	{
		/*
		 * NotificationReceiver为BroadcastReceiver的子类
		 * 用于接收推送广播并用NotificationManager通知用户也就是系统通知栏的通知
		 */
		notificationReceiver = new NotificationReceiver();

		/*
		 * ConnectivityReceiver接收手机网络状态的广播来管理xmppManager与服务器的连接与断开
		 */
		connectivityReceiver = new ConnectivityReceiver(this);

		/*
		 * 集成于android.telephony.PhoneStateListener，同上，用于监听数据链接的状态
		 */
		phoneStateListener = new PhoneStateChangeListener(this);

		// 线程池
		executorService = Executors.newSingleThreadExecutor();

		/*
		 * TaskSubmitter类包含了向上面的线程池提交一个Task任务的方法
		 */
		taskSubmitter = new TaskSubmitter(this);

		/*
		 * 任务计数器用以维护当前工作的Task
		 */
		taskTracker = new TaskTracker(this);
	}

	@Override
	public void onCreate()
	{
		myApplication = (MyApplication) getApplicationContext();
		Log.d(LOGTAG, "onCreate()...");
		telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
		// wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
		// connectivityManager = (ConnectivityManager)
		// getSystemService(Context.CONNECTIVITY_SERVICE);

		SharedPreferences settings = getSharedPreferences("yyxx_file", 0);
		String xmpport = settings.getString("xmpport", "");
		String apikey = settings.getString("apikey", "");
		String hosturl = settings.getString("hosturl", "");
		String hospitalcode = settings.getString("yydm", "");

		sharedPrefs = getSharedPreferences(Constants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);

		// Get deviceId
		deviceId = telephonyManager.getDeviceId();
		if (deviceId == null || "".equals(deviceId))
		{
			deviceId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
		}
		// myApplication.setDeviceId(deviceId);
		Log.d(LOGTAG, "deviceId=" + myApplication.getSjh());
		Editor editor = sharedPrefs.edit();
		// editor.putString(Constants.DEVICE_ID, deviceId);
		editor.putString(Constants.MOBILEPHONE, myApplication.getSjh());
		editor.putString(Constants.DEVICE_ID, deviceId);
		editor.putString(Constants.ACCOUNTNAME, myApplication.getAccount());
		editor.putString(Constants.HOSPITALCODE, hospitalcode);
		editor.putString(Constants.PCARD, myApplication.getFamilysfzhs());
		editor.putString(Constants.API_KEY, apikey);
		editor.putString(Constants.XMPP_HOST, hosturl);
		editor.putInt(Constants.XMPP_PORT, Integer.parseInt(xmpport));
		// editor.putString(Constants.XMPP_USERNAME, deviceId);
		// editor.putString(Constants.XMPP_PASSWORD, deviceId);
		editor.commit();

		// If running on an emulator
		// if (deviceId == null || deviceId.trim().length() == 0
		// || deviceId.matches("0+")) {
		// if (sharedPrefs.contains("EMULATOR_DEVICE_ID")) {
		// deviceId = sharedPrefs.getString(Constants.EMULATOR_DEVICE_ID,
		// "");
		// } else {
		// deviceId = (new StringBuilder("EMU")).append(
		// (new Random(System.currentTimeMillis())).nextLong())
		// .toString();
		// editor.putString(Constants.EMULATOR_DEVICE_ID, deviceId);
		// editor.commit();
		// }
		// }
		// Log.d(LOGTAG, "deviceId=" + deviceId);

		xmppManager = new XmppManager(this);

		taskSubmitter.submit(new Runnable()
		{
			public void run()
			{
				NotificationService.this.start();
			}
		});
	}

	@Override
	public void onStart(Intent intent, int startId)
	{
		Log.d(LOGTAG, "onStart()...");

		powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
		wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOGTAG + " PowerManager");
		wakeLock.acquire();
		wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
		wifiLock = wifiManager.createWifiLock("WifiLock");
		wifiLock.acquire();
	}

	@Override
	public void onDestroy()
	{
		Log.d(LOGTAG, "onDestroy()...");

		if (wakeLock.isHeld())
		{
			wakeLock.release();
		}
		if (wifiLock.isHeld())
		{
			wifiLock.release();
		}
		stop();
	}

	@Override
	public IBinder onBind(Intent intent)
	{
		Log.d(LOGTAG, "onBind()...");
		return null;
	}

	@Override
	public void onRebind(Intent intent)
	{
		Log.d(LOGTAG, "onRebind()...");
	}

	@Override
	public boolean onUnbind(Intent intent)
	{
		Log.d(LOGTAG, "onUnbind()...");
		return true;
	}

	public static Intent getIntent(Context context)
	{
		return new Intent(context, NotificationService.class);
	}

	public ExecutorService getExecutorService()
	{
		return executorService;
	}

	public TaskSubmitter getTaskSubmitter()
	{
		return taskSubmitter;
	}

	public TaskTracker getTaskTracker()
	{
		return taskTracker;
	}

	public XmppManager getXmppManager()
	{
		return xmppManager;
	}

	public SharedPreferences getSharedPreferences()
	{
		return sharedPrefs;
	}

	public String getDeviceId()
	{
		return deviceId;
	}

	public void connect()
	{
		Log.d(LOGTAG, "connect()...");
		taskSubmitter.submit(new Runnable()
		{
			public void run()
			{
				NotificationService.this.getXmppManager().connect();
			}
		});
	}

	public void disconnect()
	{
		Log.d(LOGTAG, "disconnect()...");
		taskSubmitter.submit(new Runnable()
		{
			public void run()
			{
				NotificationService.this.getXmppManager().disconnect();
			}
		});
	}

	private void registerNotificationReceiver()
	{
		IntentFilter filter = new IntentFilter();
		filter.addAction(Constants.ACTION_SHOW_NOTIFICATION);
		filter.addAction(Constants.ACTION_NOTIFICATION_CLICKED);
		filter.addAction(Constants.ACTION_NOTIFICATION_CLEARED);
		registerReceiver(notificationReceiver, filter);
	}

	private void unregisterNotificationReceiver()
	{
		unregisterReceiver(notificationReceiver);
	}

	private void registerConnectivityReceiver()
	{
		Log.d(LOGTAG, "registerConnectivityReceiver()...");
		telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
		IntentFilter filter = new IntentFilter();
		// filter.addAction(android.net.wifi.WifiManager.NETWORK_STATE_CHANGED_ACTION);
		filter.addAction(android.net.ConnectivityManager.CONNECTIVITY_ACTION);
		registerReceiver(connectivityReceiver, filter);
	}

	private void unregisterConnectivityReceiver()
	{
		Log.d(LOGTAG, "unregisterConnectivityReceiver()...");
		telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
		unregisterReceiver(connectivityReceiver);
	}

	private void start()
	{
		Log.d(LOGTAG, "start()...");
		// 注册通知广播接收者
		registerNotificationReceiver();

		// 注册手机网络连接状态接收者
		registerConnectivityReceiver();
		// Intent intent = getIntent();
		// startService(intent);

		// 开始与服务器进行xmpp长链接
		xmppManager.connect();
	}

	private void stop()
	{
		Log.d(LOGTAG, "stop()...");
		unregisterNotificationReceiver();
		unregisterConnectivityReceiver();
		xmppManager.disconnect();
		executorService.shutdown();
	}

	/**
	 * Class for summiting a new runnable task.
	 */
	public class TaskSubmitter
	{

		final NotificationService notificationService;

		public TaskSubmitter(NotificationService notificationService)
		{
			this.notificationService = notificationService;
		}

		@SuppressWarnings("unchecked")
		public Future submit(Runnable task)
		{
			Future result = null;
			if (!notificationService.getExecutorService().isTerminated() && !notificationService.getExecutorService().isShutdown()
					&& task != null)
			{
				result = notificationService.getExecutorService().submit(task);
			}
			return result;
		}

	}

	/**
	 * Class for monitoring the running task count.
	 */
	public class TaskTracker
	{

		final NotificationService notificationService;

		public int count;

		public TaskTracker(NotificationService notificationService)
		{
			this.notificationService = notificationService;
			this.count = 0;
		}

		public void increase()
		{
			synchronized (notificationService.getTaskTracker())
			{
				notificationService.getTaskTracker().count++;
				Log.d(LOGTAG, "Incremented task count to " + count);
			}
		}

		public void decrease()
		{
			synchronized (notificationService.getTaskTracker())
			{
				notificationService.getTaskTracker().count--;
				Log.d(LOGTAG, "Decremented task count to " + count);
			}
		}

	}

}
